/**
    package: learn-go
    filename: main
    author: diogo@gmail.com
    time: 2021/8/19 9:53
**/
package main

import (
	"fmt"
	"runtime"
	"time"
)

// 获取正在运行的函数名
func runFuncName() string {
	pc := make([]uintptr, 1)
	runtime.Callers(2, pc)
	f := runtime.FuncForPC(pc[0])
	return f.Name()
	return ""
}

// 创建一个根组件
// 如果子组件存在并发组件则父组件必须为并发组件
type RootComponent struct {
	BaseConcurrencyComponent
}

// 根组件的 方法
func (bc *RootComponent) BusinessLogicDo(resChan chan interface{}) (err error) {
	// do nothing
	fmt.Println("root component")

	ctx := GetContext(5 * time.Second)
	defer ctx.CancelFunc()

	bc.ChildsDo(ctx)

	return
}

// DemoConcurrenyComponent 创建一个并发组件
type DemoConcurrenyComponent struct {
	BaseConcurrencyComponent
}

// BusinessLogicDo 如果是并发组件, 则需要返回一个 channel
// 否则会提示超时
func (bc *DemoConcurrenyComponent) BusinessLogicDo(resChan chan interface{}) (err error) {
	// 并发组件业务逻辑填充到这
	fmt.Println(" demo Concurreny Component")

	time.Sleep(3 * time.Second)

	// 如果是并发组件, 则需要返回一个 channel
	resChan <- 2 // 写入业务执行结果
	fmt.Println(runFuncName(), "Concurreny done...")
	return
}

// DemoTwoConcurrenyComponent  创建一个并发组件
type DemoTwoConcurrenyComponent struct {
	BaseConcurrencyComponent
}

// BusinessLogicDo 如果是并发组件, 则需要返回一个 channel
// 否则会提示超时
func (bc *DemoTwoConcurrenyComponent) BusinessLogicDo(resChan chan interface{}) (err error) {
	// 并发组件业务逻辑填充到这
	fmt.Println(" Demo Two Concurreny Component")

	time.Sleep(4 * time.Second)

	// 如果是并发组件, 则需要返回一个 channel

	resChan <- 3 // 写入业务执行结果

	fmt.Println(runFuncName(), "Concurreny done...")
	return
}

//
// 创建一个普通组件
type DemoComponent struct {
	BaseComponent
}

func (bc *DemoComponent) BusinessLogicDo(resChan chan interface{}) (err error) {
	// 普通组件业务逻辑填充到这
	fmt.Println("demo components")
	fmt.Println()
	return
}

func main() {

	fmt.Println("components main demo")

	// 普通组件
	//root := &RootComponent{}
	//root.Mount(
	//    &DemoComponent{},
	//)

	// 并发组件
	root := &RootComponent{}
	root.MountConcurrency(
		&DemoConcurrenyComponent{},
		&DemoTwoConcurrenyComponent{},
	)
	// 挂载一个 普通的
	root.Mount(
		&DemoComponent{},
	)

	// 初始化业务上下文 并设置超时时间
	//ctx := GetContext(5 * time.Second)
	//defer ctx.CancelFunc()
	//root.BusinessLogicDo()
	// 开始执行子组件
	//root.ChildsDo(ctx)

	// 根组件
	root.BusinessLogicDo(nil)

}
